import os
import argparse
from multiprocessing import Process
from shutil import copyfile
import time


def run_one(module: str, root_dir: str,
            create_only: bool = True,
            synthesis: bool =True,
            implementation: bool = False,
            time_report: bool = True):
    if create_only and (synthesis or implementation or time_report):
        raise Exception("Args error")
    if time_report and not (synthesis or implementation):
        raise Exception("Args error")
    executable = 'create_project' if create_only else 'run_synth' if synthesis else 'run_impl'
    os.chdir(root_dir)
    if not os.path.exists(f"tmp/{module}"):
        os.mkdir(f"tmp/{module}")
    os.chdir(f"tmp/{module}")
    [copyfile(os.path.join("../../tcl", filename), filename)
     for filename in os.listdir("../../tcl") if filename.endswith(".tcl")]
    time_start = time.time()
    print(f"working dir: {os.getcwd()}")
    split = '\\' if os.name == 'nt' else '/'
    os.system(f"..{split}..{split}tcl{split}{executable} {module} {'true' if time_report else ''}")
    time_end = time.time()
    print(f"\t=============== module {module} finished in {(time_end - time_start):.3f}s ===============")
    if time_report:
        time_report_filenames = ["timing_report_synth.txt", "timing_report_impl.txt"]
        time_report_path = f"../../../vivado/{module}/"
        for filename in time_report_filenames:
            filepath = os.path.join(time_report_path, filename)
            if os.path.exists(filepath):
                print("\t===============", module, filename, "===============")
                with open(filepath, "r", encoding='utf8') as f:
                    lines = f.readlines()
                    for i in range(len(lines)):
                        line = lines[i]
                        if line.startswith("| Design Timing Summary"):
                            for j in range(6):
                                l = lines[i + 4 + j].replace("\n", "")
                                if len(l) != 0:
                                    print(l)
                            break


def main(*modules, **kwargs):
    if os.path.exists("scripts"):
        os.chdir("scripts")
    if not os.path.exists("tmp"):
        os.mkdir("tmp")
    root_dir = os.getcwd()
    if len(modules) == 0:
        files = [f.replace(".v", "") for f in os.listdir("../build/chisel-rtl") if f.endswith(".v") and not f.endswith(
            "Wrapper.v") and os.path.exists("../build/chisel-rtl/" + f.replace('.v', '') + "Wrapper.v")]
        print(f"all modules: {files}")
        modules = files
    try:
        # build_one(module, root_dir, create_only=create_only)
        # for multi-threads
        processes = [Process(target=run_one, args=(module, root_dir), kwargs=kwargs) for module in modules]
        [process.start() for process in processes]
        [process.join() for process in processes]
    except Exception as e:
        raise e
    finally:
        [os.remove(filename) for filename in os.listdir(".")
         if filename.endswith(".tcls") or 'backup' in filename]
        os.chdir(root_dir)


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Build modules via vivado.')
    parser.add_argument('modules', type=str, nargs="*",
                        help=f"optional list for modules to generate")
    parser.add_argument('-c', dest='create_only', action="store_true",
                        help='create projects only')
    parser.add_argument('-s', dest='synthesis', action="store_true",
                        help='create project and run to synthesis')
    parser.add_argument('-i', dest='implementation', action="store_true",
                        help='create project and run to implementation')
    parser.add_argument('-t', dest='time_report', action="store_true",
                        help='report timing summary')
    args = parser.parse_args()
    main(*args.modules,
         create_only=args.create_only,
         synthesis=args.synthesis,
         implementation=args.implementation,
         time_report=args.time_report)
